package cn.itcast.bos.web.action.base;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Controller;

import com.ctc.wstx.util.StringUtil;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

import cn.itcast.bos.domain.base.Courier;
import cn.itcast.bos.service.base.CourierService;

//添加注解，将控制层交给spring管理
@Controller
@Scope("prototype")
@Namespace("/")
@ParentPackage("json-default") // 继承struts-default
public class CourierAction extends ActionSupport implements ModelDriven<Courier> {

	// 首先运用模型驱动将表单提交的数据封装到courier对象中
	Courier courier = new Courier();

	@Override
	public Courier getModel() {

		return courier;
	}

	// 其次需要注入业务层
	@Autowired
	private CourierService courierServie;

	/**
	 * 添加快递员的方法
	 */
	@Action(value = "courier_save", results = {
			@Result(name = "success", location = "/pages/base/courier.html", type = "redirect") })
	public String save() {
		courierServie.save(courier);
		return SUCCESS;
	}

	// 属性驱动，获取请求提交的参数
	private int page;// 当前页数
	private int rows;// 每页展示的记录条数

	// 提供setter方法

	public void setPage(int page) {
		this.page = page;
	}

	public void setRows(int rows) {
		this.rows = rows;
	}

	/**
	 * 页面加载完成后将数据展现在页面的分页操作
	 */

	@Action(value = "courier_pageQuery", results = { @Result(name = "success", type = "json") })
	public String pageQuery() {

		// 将参数封装到pageable中
		Pageable pageable = new PageRequest(page-1, rows);

		
		 //根据查询条件构造Specification条件查询对象，类似Hiberbnate的QBC查询
		//这里用到了匿名内部类
		Specification<Courier>	specification=new Specification<Courier>() {

			/**
			 * 下面获取构造查询条件的方法，如果返回的值为null ,那么代表无条件查询,当页面刚刷新的时候，条件查询没有携带参数，做的是无条件的分页查询
			 * 
			 * 第一个参数root（实体类）,获取条件表达式里面的如：name=?,age=?
			 * 第二个参数query（简单查询）,构造简单的查询条件返回，提供where方法
			 * 第三个参数cb（复杂查询）,构造的Predicate对象，条件对象，构造复杂查询效果
			 */
			
			@Override
			public Predicate toPredicate(Root<Courier> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
		    //首先创建一个list结合，将获取的条件查询的结果装入，然后再转换成数组，传递到底层
			List<Predicate>	list=new ArrayList<Predicate>();
			//判断请求传递过来的参数进行非空校验courierNum,standard.name,company,type
		
			if(StringUtils.isNotBlank(courier.getCourierNum())){
				//如果快递员工号不为空，就将它的值赋给courierNum
				
				Predicate p1 = cb.equal(root.get("courierNum").as(String.class), courier.getCourierNum());
				
				list.add(p1);
			}
				
			if(StringUtils.isNotBlank(courier.getCompany())){
				//如果查询条件里面快递员所属的公司不为空，这里用到的是模糊查询 company like %?%
				
				Predicate p2 = cb.like(root.get("company").as(String.class), "%"+courier.getCompany()+"%");
				
				list.add(p2);
			}
			
			
			if(StringUtils.isNotBlank(courier.getType())){
			//条件查询框里面的派件员类型不为空，type=?
				Predicate p3 = cb.equal(root.get("type").as(String.class), courier.getType());
				
				list.add(p3);
				
				
			}
			
		   //最后一个参数收派标准的名字，要用到连接查询，不能直接赋值，要创建一个jion对象
		  //select s.c_name  from t_standard s inner join t_courier c on s.c_id=c.c_standard_id where c.c_courier_num =?
			Join<Object, Object> standardRoot = root.join("standard", JoinType.INNER);
			
			if(courier.getStandard() !=null && StringUtils.isNotBlank(courier.getStandard().getName())){
			//如果条件参数里面有standard,而且收派标准的名字不为空
			Predicate p4 = cb.like(standardRoot.get("name").as(String.class), "%"+courier.getStandard().getName()+"%");	
				
			list.add(p4);	
				
				
			}
			//将集合转换成数组new Predicate[list.size()],这里可以传递数组的元素的个数页可以传0，方法底层会根据给到的集合对象，创建相应长度的数组
			Predicate[] array = list.toArray(new Predicate[list.size()]);
			
				return cb.and(array);//and里面传递可变参数
			}
		};
		
		// 调用业务层处理数据
		Page<Courier> page = courierServie.findPageData(specification,pageable);
    
		//将数据封装到map里面
		Map<String, Object> map=new HashMap<String, Object>();
		
		map.put("total", page.getTotalElements());//所有的记录数
		map.put("rows", page.getContent());//当前页面展示的所有数据
		
		//将结果存到值栈，置顶
		//ServletActionContext.getContext().getValueStack().push(map);
		
		
		//用set存值，可以取到total，后面的 数组信息的数组是空值
		 ServletActionContext.getContext().getValueStack().set("total",page.getTotalElements());
		ServletActionContext.getContext().getValueStack().set("rows",page.getContent());
		
		return SUCCESS;
	}

	
	
	/**
	 * 作废功能courier_delBatch
	 */
    //首先获取传递过来需要作废的快递员的id值,提供模型驱动
	 private String ids;
	 
	
	public void setIds(String ids) {
		this.ids = ids;
	}
  
	
	//做完修改，要用重定向跳转页面，这样数据才可以刷新，如果是用默认的dispatcher，路径只能以/pages/....,其他的两种写法都会报路径错误，带上整个文件在项目 的位置
	@Action(value="courier_delBatch",results={@Result(name="success",location="pages/base/courier.html",type="redirect")})
    public String delBatch(){
	  
	  //将字符串按,分割成数组
	  String[] arr = ids.split(",");
	 //调用业务层，将参数传递过去
	  
	 courierServie.delBatch(arr);
	
	  return SUCCESS;
  }

/***
 * 查询还没有关联定区的快递员
 */
	@Action(value="courier_findnoassociation",results={@Result(name="success",type="json")})
	public String  findnoassociation(){
		//快递员和定区是多对多的关系
	List<Courier>	couriers=courierServie.findnoassociation();
	//将查询的信息压入值栈	
	ServletActionContext.getContext().getValueStack().push(couriers);
		return SUCCESS;
	}
	
	
}
